﻿using ImageK.Process;
using System;
using System.Collections.Generic;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ImageK.Process
{
    /** This class does bit blitting of 32-bit floating-point images. */
    public class FloatBlitter : Blitter
    {


        public static float divideByZeroValue;

        private FloatProcessor ip;
        private int width, height;
        private float[] pixels;

        static FloatBlitter() {
		    divideByZeroValue = (float) Prefs.getDouble(Prefs.DIV_BY_ZERO_VALUE, float.PositiveInfinity);
		    if (divideByZeroValue==float.MaxValue)
			    divideByZeroValue = float.PositiveInfinity;
	    }

        /** Constructs a FloatBlitter from a FloatProcessor. */
        public FloatBlitter(FloatProcessor ip)
        {
            this.ip = ip;
            width = ip.getWidth();
            height = ip.getHeight();
            pixels = (float[])ip.getPixels();
        }

        public void setTransparentColor(Color c)
        {
        }

        /** Copies the float image in 'ip' to (x,y) using the specified mode. */
        public void copyBits(ImageProcessor ip, int xloc, int yloc, int mode)
        {
            Rectangle r1, r2;
            int srcIndex, dstIndex;
            int xSrcBase, ySrcBase;
            float[] srcPixels;

            if (!(ip is FloatProcessor))
			    ip = ip.convertToFloat();
            int srcWidth = ip.getWidth();
            int srcHeight = ip.getHeight();
            r1 = new Rectangle()
            {
                Width = srcWidth,
                Height = srcHeight
            };
            r1.Location = new Point(xloc, yloc);
            r2 = new Rectangle()
            {
                Width = width,
                Height = height
            };
            if (!r1.IntersectsWith(r2))
                return;
            srcPixels = (float[])ip.getPixels();
            r1.Intersect(r2);
            xSrcBase = (xloc<0) ? -xloc : 0;
            ySrcBase = (yloc<0) ? -yloc : 0;
            bool useDBZValue = !float.IsFinite(divideByZeroValue);
            float src, dst;
            for (int y = r1.Y; y<(r1.Y+r1.Height); y++)
            {
                srcIndex = (y-yloc)*srcWidth + (r1.X-xloc);
                dstIndex = y * width + r1.X;
                switch (mode)
                {
                    case Blitter.COPY:
                    case Blitter.COPY_INVERTED:
                    case Blitter.COPY_TRANSPARENT:
                        for (int i = r1.Width; --i>=0;)
                            pixels[dstIndex++] = srcPixels[srcIndex++];
                        break;
                    case Blitter.COPY_ZERO_TRANSPARENT:
                        for (int i = r1.Width; --i>=0;)
                        {
                            src = srcPixels[srcIndex++];
                            if (src==0f)
                                dst = pixels[dstIndex];
                            else
                                dst = src;
                            pixels[dstIndex++] = dst;
                        }
                        break;
                    case Blitter.ADD:
                        for (int i = r1.Width; --i>=0; srcIndex++, dstIndex++)
                            pixels[dstIndex] = srcPixels[srcIndex]+pixels[dstIndex];
                        break;
                    case Blitter.AVERAGE:
                        for (int i = r1.Width; --i>=0;)
                        {
                            dst =(srcPixels[srcIndex++]+pixels[dstIndex])/2;
                            pixels[dstIndex++] = dst;
                        }
                        break;
                    case Blitter.DIFFERENCE:
                        for (int i = r1.Width; --i>=0; srcIndex++, dstIndex++)
                        {
                            dst = pixels[dstIndex]-srcPixels[srcIndex];
                            pixels[dstIndex] = dst<0 ? -dst : dst;
                        }
                        break;
                    case Blitter.SUBTRACT:
                        for (int i = r1.Width; --i>=0; srcIndex++, dstIndex++)
                            pixels[dstIndex] = pixels[dstIndex]-srcPixels[srcIndex];
                        break;
                    case Blitter.MULTIPLY:
                        for (int i = r1.Width; --i>=0; srcIndex++, dstIndex++)
                            pixels[dstIndex] = srcPixels[srcIndex]*pixels[dstIndex];
                        break;
                    case Blitter.DIVIDE:
                        for (int i = r1.Width; --i>=0; srcIndex++, dstIndex++)
                        {
                            src = srcPixels[srcIndex];
                            if (useDBZValue && src==0.0)
                                pixels[dstIndex] = divideByZeroValue;
                            else
                                pixels[dstIndex] = pixels[dstIndex]/src;
                        }
                        break;
                    case Blitter.AND:
                        for (int i = r1.Width; --i>=0;)
                        {
                            dst = (int)srcPixels[srcIndex++]&(int)pixels[dstIndex];
                            pixels[dstIndex++] = dst;
                        }
                        break;
                    case Blitter.OR:
                        for (int i = r1.Width; --i>=0;)
                        {
                            dst = (int)srcPixels[srcIndex++]|(int)pixels[dstIndex];
                            pixels[dstIndex++] = dst;
                        }
                        break;
                    case Blitter.XOR:
                        for (int i = r1.Width; --i>=0;)
                        {
                            dst = (int)srcPixels[srcIndex++]^(int)pixels[dstIndex];
                            pixels[dstIndex++] = dst;
                        }
                        break;
                    case Blitter.MIN:
                        for (int i = r1.Width; --i>=0;)
                        {
                            src = srcPixels[srcIndex++];
                            dst = pixels[dstIndex];
                            if (src<dst) dst = src;
                            pixels[dstIndex++] = dst;
                        }
                        break;
                    case Blitter.MAX:
                        for (int i = r1.Width; --i>=0;)
                        {
                            src = srcPixels[srcIndex++];
                            dst = pixels[dstIndex];
                            if (src>dst) dst = src;
                            pixels[dstIndex++] = dst;
                        }
                        break;
                }
            }
	    }
    }

}
